/**
 * 
 */
package org.gbif.metadata.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;

import javax.servlet.ServletContext;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.io.SAXReader;
import org.gbif.metadata.eml.Abstract;
import org.gbif.metadata.eml.Dataset;
import org.gbif.metadata.eml.Eml;
import org.gbif.metadata.eml.IndividualName;
import org.gbif.metadata.eml.Maintenance;
import org.gbif.metadata.eml.MaintenanceDescription;
import org.gbif.metadata.eml.Purpose;
import org.jibx.runtime.BindingDirectory;
import org.jibx.runtime.IBindingFactory;
import org.jibx.runtime.IMarshallingContext;
import org.jibx.runtime.IUnmarshallingContext;
import org.jibx.runtime.JiBXException;

/**
 * File Utilities
 * 
 * @author davemartin
 */
public class EmlUtils {
    protected static final Log log = LogFactory.getLog(EmlUtils.class);
	protected static final String requiredNamespace = "eml://ecoinformatics.org/eml-2.0.1";
	protected static final String requiredNamespacePrefix = "eml";
	public static final String METADATA_SYSTEM = "GBIF Metadata Editor";

	public static Eml newDoc(String guid, String title, String description, String contactName, String contactEmail){
		Eml eml = Eml.newInstance();
		// basic dataset info
		eml.updateDataset(guid, title, description, contactName, contactEmail);
		// set the package Id
		eml.setPackageId("org.gbif.eml." + guid);
		eml.setSystem(METADATA_SYSTEM);
		return eml;
	}
	
	public static Eml parseEml(File emlFile) throws JiBXException, IOException {
		// dom4j parse it
		IBindingFactory bfact = BindingDirectory.getFactory(Eml.class);
		IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
		Eml eml = (Eml) uctx.unmarshalDocument(new FileInputStream(emlFile), null);
		return eml;
	}
	
	public static void writeFile(File file, Eml doc) throws Exception{
		log.debug("Writing metadata out to file");

		checkPurposeAndMaintenance(doc);

		IBindingFactory bfact = BindingDirectory.getFactory(Eml.class);
		IMarshallingContext mctx = bfact.createMarshallingContext();

		if (file == null) {
			throw new IllegalArgumentException("File parameter needed");
		}
		if (!file.exists()){
			FileUtils.forceMkdir(file.getParentFile());
			file.createNewFile();
		}
		mctx.marshalDocument(doc, "UTF-8", true, new FileOutputStream(file));
	}
	 
	/**
	 * Populate Purpose and Maintenance - required for Metacat compatibility.
	 * 
	 * @param eml
	 */
	private static void checkPurposeAndMaintenance(Eml eml) {
		if (eml.getDataset().getPurpose() == null
				|| eml.getDataset().getPurpose().getPara() == null) {
			Purpose purpose = new Purpose();
			purpose.setPara("TODO");
			eml.getDataset().setPurpose(purpose);
		}

		if (eml.getDataset().getMaintenance() == null
				|| eml.getDataset().getMaintenance().getDescription() == null) {
			Maintenance m = new Maintenance();
			MaintenanceDescription d = new MaintenanceDescription();
			d.setPara("TODO");
			m.setDescription(d);
			eml.getDataset().setMaintenance(m);
		}
	}
	
	public static Eml parseEml(String documentBody) throws IOException, JiBXException {
		Eml eml = null;
		if (StringUtils.isNotBlank(documentBody)) {
			File file = newTmpFile();
			log.debug("Importing pasted document");
			FileOutputStream out = new FileOutputStream(file);
			out.write(documentBody.getBytes());
			eml = parseEml(file); 
		}
		return eml;
	}
	
	public static Eml parseEml(URL emlUrl) throws IOException, JiBXException{
		Eml eml = null;
		if (emlUrl!=null) {
			log.debug("Importing via url:"+emlUrl);
			HttpClient client = new HttpClient();
			GetMethod getMethod = new GetMethod(emlUrl.toString());
			int responseCode = client.executeMethod(getMethod);
			log.debug("Response code: " + responseCode);
			InputStream input = getMethod.getResponseBodyAsStream();
			File file = outputToFile(input);
			eml = parseEml(file); 
		}
		return eml;
	}
	
	/**
	 * Output to local file system.
	 * 
	 * @param input
	 * @return
	 * @throws IOException
	 * @throws FileNotFoundException
	 */
	private static File outputToFile(InputStream input) throws IOException {
		File currentDoc = newTmpFile();
		FileOutputStream output = new FileOutputStream(currentDoc);

		byte[] buf = new byte[1024];
		int len;
		while ((len = input.read(buf)) > 0) {
			output.write(buf, 0, len);
		}
		output.flush();
		return currentDoc;
	}
	
	/**
	 * Check the namespace of the supplied file, adding the mandatory
	 * eml namespace if required.
	 * 
	 * @param file
	 */
	private void checkNamespaces(File file) {
		
		SAXReader reader = new SAXReader();
		org.dom4j.Document document;
		try {
			document = reader.read(new FileInputStream(file));
			Namespace namespace = document.getRootElement().getNamespace();
			if (namespace == null
					|| (StringUtils.isBlank(namespace.getPrefix()) && StringUtils
							.isBlank(namespace.getURI()))) {

				Element element = document.getRootElement();
				element.setName("eml:eml");
				document.getRootElement().addNamespace(requiredNamespacePrefix,requiredNamespace);

				log.debug("Adding namespaces to document");
				file.delete();
				file.createNewFile();
				OutputStream outputStream = FileUtils.openOutputStream(file);
				outputStream.write(document.asXML().getBytes());
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
	}

	public static File newTmpFile() throws IOException {
		return File.createTempFile("ipt-eml","eml");
	}	
}
